#ifndef DEVICE_H
#define DEVICE_H
#include <optixu/optixu_math_namespace.h> 

struct ViewRayData
{ 
  optix::uint   depth;
	optix::float3 position;
	optix::float3 normal;
};

struct PhotonRayData
{
	optix::uint depth;
	optix::uint nPhotons;
	optix::float3 energy;
	optix::uint2 sample;
};

struct PhotonRec
{
	optix::float3 pos;
	optix::float3 normal;
	optix::float3 incDir;
	optix::float3 energy;
	optix::uint axis;
	optix::float3 pad;
};

struct Light 
{
	optix::float3 anchor;
	optix::float3 v1;
	optix::float3 v2;
	
	optix::float3 power;
};

// sample hemisphere with cosine density
__device__ __inline__ void sampleUnitHemisphere( const optix::float2& sample,
                                                 const optix::float3& U,
                                                 const optix::float3& V,
                                                 const optix::float3& W,
                                                 optix::float3& point )
{
    using namespace optix;

    float phi = 2.0f * M_PIf*sample.x;
    float r = sqrt( sample.y );
    float x = r * cos(phi);
    float y = r * sin(phi);
    float z = 1.0f - x*x -y*y;
    z = z > 0.0f ? sqrt(z) : 0.0f;

    point = x*U + y*V + z*W;
}

// Create ONB from normal.  Resulting W is Parallel to normal
__device__ __inline__ void createONB( const optix::float3& n,
                                      optix::float3& U,
                                      optix::float3& V,
                                      optix::float3& W )
{
  using namespace optix;

  W = normalize( n );
  U = cross( W, make_float3( 0.0f, 1.0f, 0.0f ) );
  if ( fabsf( U.x) < 0.001f && fabsf( U.y ) < 0.001f && fabsf( U.z ) < 0.001f  )
    U = cross( W, make_float3( 1.0f, 0.0f, 0.0f ) );
  U = normalize( U );
  V = cross( W, U );
}

#endif